
package com.scs.application.modules.order.controller;


import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.exceptions.ExportException;
import com.scs.application.core.exceptions.ImportException;
import com.scs.application.core.model.CommonResult;
import com.scs.application.core.model.ImportResult;
import com.scs.application.core.model.PageResult;
import com.scs.application.core.model.RestResult;
import com.scs.application.core.mvc.controller.CrudController;
import com.scs.application.core.mvc.controller.ImAndExAbleController;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.entity.SysLog;
import com.scs.application.modules.order.consts.DictConsts;
import com.scs.application.modules.order.dto.CloseOrderDto;
import com.scs.application.modules.order.dto.ExcelPurchaseOrderDTO;
import com.scs.application.modules.order.dto.OrderDTO;
import com.scs.application.modules.order.entity.PurchaseOrder;
import com.scs.application.modules.order.entity.PurchaseProcess;
import com.scs.application.modules.order.request.PurchaseOrderQueryRequest;
import com.scs.application.modules.order.request.ScanQrcodeRequest;
import com.scs.application.modules.order.service.PurchaseOrderItemService;
import com.scs.application.modules.order.service.PurchaseOrderService;
import com.scs.application.modules.order.vo.ExcelPurchaseOrderVO;
import com.scs.application.modules.order.vo.PurchaseOrderVO;
import com.scs.application.modules.thirdparty.erp.request.CloseOrderRequest;
import com.scs.application.modules.thirdparty.erp.request.OrderRequest;
import com.scs.application.modules.thirdparty.erp.request.OrderStatusRequest;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 采购订单 controller
 *
 */
@AllArgsConstructor
@RestController
@RequestMapping("/order/purchase_orders")
public class PurchaseOrderController extends CrudController<PurchaseOrder, String, PurchaseOrderService> implements ImAndExAbleController<PurchaseOrderQueryRequest> {


    private final PurchaseOrderItemService purchaseOrderItemService;


    @PostMapping
    public CommonResult add(@RequestBody @Valid PurchaseOrder entity) {
        PurchaseOrder purchaseOrder = service.add(entity);
        return CommonResult.ok("新增成功", purchaseOrder);
    }

    // 供应商自己新增或者更新
    @RequestMapping(value = "/addForSp", method = RequestMethod.POST)
    public CommonResult addForSp(@RequestBody PurchaseOrder entity) {
        entity.setSupplierId(UserUtils.getSupplier().getId());
        entity.setSupplierName(UserUtils.getSupplier().getName());
        PurchaseOrder purchaseOrder = service.addForSp(entity);
        return CommonResult.ok("操作成功", purchaseOrder);
    }

    @GetMapping("/page")
    public PageResult page(PurchaseOrderQueryRequest request) {
        IPage page = service.page(request);
        return PageResult.ok("查询成功", page.getRecords(), page.getTotal());
    }


    @GetMapping("/list")
    public CommonResult list(PurchaseOrderQueryRequest request) {
        List<PurchaseOrder> list = service.list(request);
        return CommonResult.ok("查询成功", list);
    }

    /**
     * 医院提交采购订单
     *
     * @param id
     * @return
     */
    @PostMapping("/submit_order/{id}")
    public CommonResult submitOrder(@PathVariable("id") String id) {
        service.submitOrder(id);
        return CommonResult.ok("提交成功");
    }

    /**
     * 医院采购订单审核通过
     *
     * @param id
     * @return
     */
    @PostMapping("/pass/{id}")
    public CommonResult passOrder(@PathVariable("id") String id) {
        service.passOrder(id);
        return CommonResult.ok("通过成功");
    }

    /**
     * 医院采购订单取消提交
     *
     * @param id
     * @return
     */
    @PostMapping("/cancel/{id}")
    public CommonResult cancelOrder(@PathVariable("id") String id) {
        service.cancelOrder(id);
        return CommonResult.ok("退回成功");
    }

    /**
     * 关闭订单
     *
     * @param dto
     * @return
     */
    @PostMapping("/close")
    public CommonResult closeOrder(@RequestBody CloseOrderDto dto) {
        if (StringUtils.isBlank(dto.getUser())) {
            try {
                dto.setUser(UserUtils.currentUser().getNickname());
            }catch (Exception e) {

            }
        }
        service.closeOrder(dto);
        // 操作日志
        PurchaseOrder main = service.getById(dto.getId());
        if (main != null) {
            syslogSuccess(
                    SysLog.moduleType.order,
                    "关闭订单",
                    main.getId(),
                    main.getCode(),
                    UserUtils.currentUser().getNickname(),
                    StrUtil.format("原因:{}",dto.getReason())
            );
        }
        return CommonResult.ok("作废成功");
    }

    /**
     * 供应商订单列表页
     *
     * @param request
     * @return
     */
    @GetMapping("/page_for_supplier")
    public PageResult pageForSupplier(PurchaseOrderQueryRequest request) {
        IPage page = service.pageForSupplier(request);
        return PageResult.ok("查询成功", page.getRecords(), page.getTotal());
    }

    /**
     * 供应商订单新增列表界面
     *
     * @param request
     * @return
     */
    @GetMapping("/page_for_supplier_add")
    public PageResult pageForSupplierAdd(PurchaseOrderQueryRequest request) {
        IPage page = service.pageForSupplierAdd(request);
        return PageResult.ok("查询成功", page.getRecords(), page.getTotal());
    }


    /**
     * @param request
     * @Description: 查询未发货和部分发货订单
     * @return: com.scs.application.core.model.PageResult
     */
    @GetMapping("/page_for_delivery")
    public PageResult pageForDelivery(PurchaseOrderQueryRequest request) {
        IPage page = service.pageForDelivery(request);
        return PageResult.ok("查询成功", page.getRecords(), page.getTotal());
    }

    /**
     *  ERP 获取订单
     * @param request
     * @return
     */
    public CommonResult<List<PurchaseOrderVO>> getOrdersERP(OrderRequest request) {
        return service.getOrdersERP(request.getHospitalId(), request.getOrderDate(), request.getCodes());
    }

    /**
     * ERP 关闭订单
     * @param request
     * @return
     */
    public CommonResult closeOrderERP(CloseOrderRequest request) {
        PurchaseOrder p = service.getOne(
                Wrappers.<PurchaseOrder>query().eq("code", request.getCode())
                        .eq("hospital_id", request.getHospitalId())
        );
        if (p == null){
            throw new BusinessException("未找到该单号相关信息，请输入正确的单号");
        }
        CloseOrderDto closeOrderDto = new CloseOrderDto().setId(p.getId()).setReason(request.getCloseReason()).setUser(request.getUser()).setFlagDeliveryClose(request.getFlagDeliveryClose());
        service.closeOrder(closeOrderDto);

        //添加到订单业务进程表 院方关闭订单
        PurchaseProcess purchaseProcess = new PurchaseProcess();
        purchaseProcess.setHospitalId(request.getHospitalId())
                .setHospitalName(p.getHospitalName())
                .setSupplierId(p.getSupplierId())
                .setSupplierName(p.getSupplierName())
                .setPoId(p.getId())
                .setGmtCreate(new Date());
        purchaseProcess.setContent(p.getCode() + "订单被取消").setType(DictConsts.TYPE_HOSPITAL_CANCEL);
        return CommonResult.ok("关闭成功");
    }

    /**
     * 通过接口回传订单状态（取消、无法供货、部分发货、全部发货）
     *
     * @param list
     * @return
     */
    public CommonResult callStatus(List<OrderStatusRequest> list) {
        return service.callStatus(list);
    }

    /**
     * 确认可供货
     *
     * @param id
     * @return
     */
    @PostMapping("/able/{id}")
    public CommonResult able(@PathVariable("id") String id) {
        service.saveAndSend(service.getById(id),false);
        // 操作日志
        PurchaseOrder main = service.getById(id);
        if (main != null) {
            syslogSuccess(
                    SysLog.moduleType.order,
                    "确认供货",
                    main.getId(),
                    main.getCode(),
                    UserUtils.currentUser().getNickname(),
                    ""
            );
        }
        return CommonResult.ok();
    }

    /**
     * 确认不可供货
     *
     * @param dto
     * @return
     */
    @PostMapping("/disable")
    public CommonResult disable(@RequestBody CloseOrderDto dto) {
        if (StringUtils.isBlank(dto.getUser())) {
            try {
                dto.setUser(UserUtils.currentUser().getNickname());
            }catch (Exception e) {

            }
        }
        service.disable(dto);
        // 操作日志
        PurchaseOrder main = service.getById(dto.getId());
        if (main != null) {
            syslogSuccess(
                    SysLog.moduleType.order,
                    "无法供货",
                    main.getId(),
                    main.getCode(),
                    UserUtils.currentUser().getNickname(),
                    StrUtil.format("原因:{}",dto.getReason())
            );
        }
        return CommonResult.ok("操作成功");
    }


    @Override
    public void excelExport(PurchaseOrderQueryRequest request) throws ExportException {
        String fileName = "订单信息" + DateUtils.format(DateUtils.now(), "yyyyMMddHHmmss") + ".xlsx";

        ExportParams params = PoiUtils.getDefaultExportParams("订单导出", "订单信息", true);

        request.setHospitalId(UserUtils.getHospitalId());
        List<ExcelPurchaseOrderVO> list = service.listExcel(request);
        List<ExcelPurchaseOrderDTO> dtos = Lists.newArrayListWithCapacity(list.size());
        BeanUtils.copyProperties(list, dtos, ExcelPurchaseOrderDTO.class);

        try {
            setDownloadParam(fileName);
            PoiUtils.exportExcel(response().getOutputStream(), params, ExcelPurchaseOrderDTO.class, dtos);
        } catch (IOException e) {
            throw new ExportException("导出异常", e);
        }
    }


    @Override
    public void excelTemplate(PurchaseOrderQueryRequest request) {
        String fileName = "订单导入模板.xlsx";
        ExportParams params = PoiUtils.getDefaultExportParams("订单导入模板", "订单信息", true);
        try {
            setDownloadParam(fileName);
            ExcelPurchaseOrderDTO mockData = PoiUtils.mockData(ExcelPurchaseOrderDTO.class);
            PoiUtils.exportExcel(response().getOutputStream(), params, ExcelPurchaseOrderDTO.class, Lists.newArrayList(mockData));
        } catch (IOException e) {
            throw new ExportException("导出异常", e);
        }
    }

    @Override
    public CommonResult<ImportResult> excelImport(MultipartFile file) throws ImportException {
        return CommonResult.ok("导入成功", service.excelImport(file));
    }

    /**
     * 导入.txt
     */
    @PostMapping({"/txt/getTxtDataList"})
    private CommonResult getTxtDataList(MultipartFile file) throws IOException {

        String purchaseOrder = new String(file.getBytes(), "UTF-8");
        List<OrderDTO> dtos = JSON.parseArray(purchaseOrder, OrderDTO.class);
        boolean isTxt = true;
        service.batchSaveForDTO(dtos, isTxt);
        return CommonResult.ok("导入成功");
    }

    /**
     * 统计昨日收益、本月收益、今年收益、累计收益、以及 收益曲线数据
     *
     * @return
     */
    @GetMapping("/earning_statistics")
    public CommonResult<Map<String, Object>> getEarningStatistics() {
        Map<String, Object> result = Maps.newHashMap();

        // 查询昨日收益、本月收益、今年收益、累计收益
        QueryWrapper<PurchaseOrder> wrapper = Wrappers.<PurchaseOrder>query()
                .select("sum(total_amount)")
                .notIn("status", DictConsts.STATUS_UNSUBMIT, DictConsts.STATUS_UNPASS)
                .eq("is_closed", GlobalConsts.NO_STR);
        if (UserUtils.isSupplier()) {
            wrapper.eq("supplier_id", UserUtils.getSupplierId());
        }
        if (UserUtils.isHospital()) {
            wrapper.eq("hospital_id", UserUtils.getHospitalId());
        }


        Date now = new Date();

        // 昨天收益
        QueryWrapper<PurchaseOrder> yesterdayWrapper = wrapper.clone();
        Date yesterday = DateUtils.addDays(now, -1);
        yesterdayWrapper.between("gmt_create", DateUtils.format(yesterday, "yyyy-MM-dd 00:00:00"),
                DateUtils.format(yesterday, "yyyy-MM-dd 23:59:59"));
        Double yesterdayEarning = service.getObj(yesterdayWrapper, o -> objMapper(o));
        result.put("yesterdayEarning", yesterdayEarning == null ? 0 : yesterdayEarning);

        // 本月收益
        Date firstDayOfMonth = DateUtils.getFirstDayOfMonth(now);
        Date lastDayOfMonth = DateUtils.getLastDayOfMonth(now);
        QueryWrapper<PurchaseOrder> thisMonthWrapper = wrapper.clone();
        thisMonthWrapper.between("gmt_create", DateUtils.format(firstDayOfMonth, "yyyy-MM-dd 00:00:00"),
                DateUtils.format(lastDayOfMonth, "yyyy-MM-dd 23:59:59"));
        Double thisMonthEarning = service.getObj(thisMonthWrapper, o -> objMapper(o));
        result.put("thisMonthEarning", thisMonthEarning == null ? 0 : thisMonthEarning);

        // 累计收益
        QueryWrapper<PurchaseOrder> totalWrapper = wrapper.clone();
        Double totalEarning = service.getObj(totalWrapper, o -> objMapper(o));
        result.put("totalEarning", totalEarning == null ? 0 : totalEarning);

        // ===============================收益曲线 开始============================================
        QueryWrapper<PurchaseOrder> barWrapper = wrapper.clone();
        barWrapper.select("total_amount,gmt_create");

        List<PurchaseOrder> orders = service.list(barWrapper);

        // 日收益（本月每日）
        Map<String, Double> dayData = Maps.newLinkedHashMap();
        orders.stream().filter(order -> {
            Date gmtCreate = order.getGmtCreate();
            String pattern = "yyyy-MM-dd";
            Date thisDayOfPrevMonth = DateUtils.addDays(now, -31);

            return DateUtils.format(gmtCreate, pattern).compareTo(DateUtils.format(thisDayOfPrevMonth, pattern)) >= 0 &&
                    DateUtils.format(gmtCreate, pattern).compareTo(DateUtils.format(now, pattern)) <= 0;
        }).collect(Collectors.toMap(o -> DateUtils.format(o.getGmtCreate(), "MM-dd"), o -> o.getTotalAmount(), (v1, v2) -> Double.sum(v1, v2)))
                .entrySet().stream().sorted(Map.Entry.comparingByKey())
                .forEachOrdered(entry -> dayData.put(entry.getKey(), entry.getValue()));
        result.put("dayData", dayData);

        // 月收益（最近12个月）
        Map<String, Double> monthData = Maps.newLinkedHashMap();
        orders.stream().filter(order -> {
            Date gmtCreate = order.getGmtCreate();
            String pattern = "yyyy-MM";
            Date thisMonthOfPrevYear = DateUtils.addMonths(now, -12);
            return DateUtils.format(gmtCreate, pattern).compareTo(DateUtils.format(thisMonthOfPrevYear, pattern)) >= 0 &&
                    DateUtils.format(gmtCreate, pattern).compareTo(DateUtils.format(now, pattern)) <= 0;
        }).collect(Collectors.toMap(o -> DateUtils.format(o.getGmtCreate(), "yyyy-MM"), o -> o.getTotalAmount(), (v1, v2) -> Double.sum(v1, v2)))
                .entrySet().stream().sorted(Map.Entry.comparingByKey())
                .forEachOrdered(entry -> monthData.put(entry.getKey(), entry.getValue()));
        result.put("monthData", monthData);

        // 年收益
        Map<String, Double> yearData = Maps.newLinkedHashMap();
        orders.stream().filter(order -> {
            Date gmtCreate = order.getGmtCreate();
            String pattern = "yyyy";
            Date thisMonthOfPrevYear = DateUtils.addMonths(now, -12);
            return DateUtils.format(gmtCreate, pattern).compareTo(DateUtils.format(thisMonthOfPrevYear, pattern)) >= 0 &&
                    DateUtils.format(gmtCreate, pattern).compareTo(DateUtils.format(now, pattern)) <= 0;
        }).collect(Collectors.toMap(o -> DateUtils.format(o.getGmtCreate(), "yyyy"), o -> o.getTotalAmount(), (v1, v2) -> Double.sum(v1, v2)))
                .entrySet().stream().sorted(Map.Entry.comparingByKey())
                .forEachOrdered(entry -> yearData.put(entry.getKey(), entry.getValue()));
        result.put("yearData", yearData);

        // ===============================收益曲线 结束============================================

        return CommonResult.ok("查询成功", result);
    }

    private Double objMapper(Object value) {
        if (value == null) {
            return 0.0;
        }
        if (value instanceof BigDecimal) {
            return ((BigDecimal) value).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        return 0.0;
    }

    @PostMapping("/scan_qrcode")
    public CommonResult scanQrcode(@RequestBody ScanQrcodeRequest request) {
        JSONObject resultJson = service.loadPoQrcode(request);
        return CommonResult.ok("操作成功", resultJson);
    }

    /***
     * @param entity
     * @Description:  通用保存、更新
     */
    @PostMapping("/saveOrUpdateCommon")
    public RestResult saveOrUpdateCommon(@Valid @RequestBody PurchaseOrder entity) {
        if (entity.isNewRecord()){
            service.add(entity);
        }else {
            service.updateById(entity);
        }
        return RestResult.ok("数据保存成功", entity);
    }

    /**
     * @description: 保存采购订单，并发货
     * @author: Tai
     * @date: 2024/10/13 23:18
     * @param:
     * @return:
     **/
    @PostMapping("/saveAndSend")
    public CommonResult saveAndSend(@Valid @RequestBody PurchaseOrder entity) {
        service.saveAndSend(entity,true);
        // 操作日志
        PurchaseOrder main = service.getById(entity.getId());
        if (main != null) {
            syslogSuccess(
                    SysLog.moduleType.order,
                    "发货",
                    main.getId(),
                    main.getCode(),
                    UserUtils.currentUser().getNickname(),
                    ""
            );
        }
        return CommonResult.ok();
    }

}
